package com.starlink.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.hutool.core.convert.Convert;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.starlink.client.ras.RasClient;
import com.starlink.client.ras.request.GoodsBindingRequest;
import com.starlink.client.ras.request.WrapAuditListRequest;
import com.starlink.client.ras.response.RasBaseResponse;
import com.starlink.client.ras.response.WrapAuditListResponse;
import com.starlink.common.domain.BaseEntity;
import com.starlink.mapper.MallBooksMapper;
import com.starlink.model.domain.*;
import com.starlink.model.request.*;
import com.starlink.model.util.SchoolbagGroupBagBooksConvert;
import com.starlink.model.vo.*;
import com.starlink.service.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.domain.Pageable;
import com.starlink.common.utils.AssertUtil;
import com.starlink.model.dtomapper.SchoolbagGroupBagDtoMapper;
import com.starlink.mapper.SchoolbagGroupBagMapper;
import com.starlink.model.util.SchoolbagGroupBagConvert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import static com.starlink.utils.PageUtils.getOrderBy;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhanghong
 */
@Service
public class SchoolbagGroupBagServiceImpl extends ServiceImpl<SchoolbagGroupBagMapper, SchoolbagGroupBagDO> implements SchoolbagGroupBagService {
    @Autowired
    private SchoolbagGroupBagMapper schoolbagGroupBagMapper;
    @Autowired
    private SchoolbagGroupBagBooksService schoolbagGroupBagBooksService;
    @Autowired
    private SchoolbagBooksStorageService schoolbagBooksStorageService;
    @Autowired
    private SchoolbagBooksService schoolbagBooksService;
    @Autowired
    private MallBooksMapper mallBooksMapper;
    @Autowired
    private SchoolbagService schoolbagService;
    @Autowired
    private SchoolbagSpecificationService schoolbagSpecificationService;
    @Autowired
    private SchoolbagGroupService schoolbagGroupService;
    @Autowired
    private RasClient rasClient;
    @Autowired
    private SchoolbagPhaseService schoolbagPhaseService;
    @Autowired
    private SchoolbagPhaseBooksService schoolbagPhaseBooksService;

    @Override
    public SchoolbagGroupBagVO getByKey(long id) {
        SchoolbagGroupBagVO schoolbagGroupBagVO = SchoolbagGroupBagDtoMapper.INSTANCE.do2VO(getById(id));
        // 查询书包书籍列表
        if (schoolbagGroupBagVO == null) {
            return null;
        }

        List<SchoolbagGroupBagBooksDO> bagBooksList = schoolbagGroupBagBooksService.lambdaQuery()
                .eq(SchoolbagGroupBagBooksDO::getCategoryId, schoolbagGroupBagVO.getCategoryId())
                .eq(SchoolbagGroupBagBooksDO::getGroupId, schoolbagGroupBagVO.getGroupId())
                .eq(SchoolbagGroupBagBooksDO::getBagId, schoolbagGroupBagVO.getId())
                .list();

        List<SchoolbagGroupBagBooksVO> bagBooks = SchoolbagGroupBagBooksConvert.buildSchoolbagGroupBagBooksVoList(bagBooksList);
        for (SchoolbagGroupBagBooksVO bagBook : bagBooks) {
            // 查询对应的书籍芯片码
            SchoolbagBooksStorageVO storageVO = schoolbagBooksStorageService.getByKey(bagBook.getStorageBookId());
            if (storageVO!=null) {
                bagBook.setStorageBookRasCode(storageVO.getRasCode());
            }
            // 查询对应的书籍信息
            SchoolbagBooksVO booksVO = schoolbagBooksService.getByKey(bagBook.getBookId());
            if (booksVO != null) {
                // 书籍信息
                MallBooksDO mallBooksDO = mallBooksMapper.selectDOById(booksVO.getMallBooksId());
                if (mallBooksDO != null) {
                    bagBook.setTitle(mallBooksDO.getTitle());
                    bagBook.setPicture(mallBooksDO.getPicture());
                    bagBook.setAuthor(mallBooksDO.getAuthor());
                    bagBook.setPublishingHouse(mallBooksDO.getPublishingHouse());
                }
            }
        }
        schoolbagGroupBagVO.setBagBooks(bagBooks);
        return schoolbagGroupBagVO;
    }

    @Override
    public PageInfo<SchoolbagGroupBagVO> pageQuery(Pageable pageable,SchoolbagGroupBagRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize(), getOrderBy(pageable.getSort())).setReasonable(true);
        List<SchoolbagGroupBagDO> list = schoolbagGroupBagMapper.listQuery(request);
        List<SchoolbagGroupBagVO> schoolbagGroupBagVOList = SchoolbagGroupBagConvert.buildSchoolbagGroupBagVoList(list);
        return new PageInfo(schoolbagGroupBagVOList);
    }

    @Override
    public List<SchoolbagGroupBagVO> listQuery(SchoolbagGroupBagRequest request) {
        List<SchoolbagGroupBagDO> list = schoolbagGroupBagMapper.selectDOList(SchoolbagGroupBagDtoMapper.INSTANCE.request2DO(request));
        List<SchoolbagGroupBagVO> schoolbagGroupBagVOS = SchoolbagGroupBagConvert.buildSchoolbagGroupBagVoList(list);
        return schoolbagGroupBagVOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(SchoolbagGroupBagRequest request) {
//        SchoolbagGroupBagDO entity = SchoolbagGroupBagDtoMapper.INSTANCE.request2DO(request);
//        if (save(entity)) {
//            // 插入关联的数据
//            for (Long storageBookId : request.getStorageBookIds()) {
//                SchoolbagGroupBagBooksRequest booksRequest = new SchoolbagGroupBagBooksRequest();
//                booksRequest.setCategoryId(request.getCategoryId());
//                booksRequest.setGroupId(request.getGroupId());
//                booksRequest.setBagId(entity.getId());
//                booksRequest.setStorageBookId(storageBookId);
//                schoolbagGroupBagBooksService.add(booksRequest);
//            }
//        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByKey(SchoolbagGroupBagRequest request) {
        AssertUtil.assertNotNull(request.getId(), "id不能为空");
        saveOrUpdate(SchoolbagGroupBagDtoMapper.INSTANCE.request2DO(request));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteDOByIds(String ids) {
        schoolbagGroupBagMapper.deleteDOByIds(Convert.toStrArray(ids));
        return true;
    }

    @Transactional
    @Override
    public Boolean batchAdd(SchoolbagGroupBagListOperationRequest request) {
        // 第一步：校验
        AssertUtil.assertNotNull(request.getCategoryId(), "书包类型id不能为空");
        AssertUtil.assertNotNull(request.getGroupId(), "书包所属分组不能为空");
        AssertUtil.assertNotEmpty(request.getBagList(), "书包所属分组不能为空");
//        AssertUtil.assertTrue(request.getBagList().size() == 12, "书包个数必须为12个");

        // 查询类别
        SchoolbagDO category = schoolbagService.lambdaQuery().eq(BaseEntity::getId, request.getCategoryId()).last("limit 1").one();
        AssertUtil.assertNotNull(category, "书包类型不存在");
        String specification = category.getSpecification();
        AssertUtil.assertNotNull(specification, "书包规格期数不能为空");
        AssertUtil.assertTrue(NumberUtil.isNumber(specification), "书包规格期数必须为数字");

        // 查询规格
        SchoolbagSpecificationDO spec = schoolbagSpecificationService.lambdaQuery().eq(SchoolbagSpecificationDO::getSchoolbagId, category.getId()).eq(BaseEntity::getId, request.getSpecId()).last("limit 1").one();
        AssertUtil.assertNotNull(spec, "书包规格不存在");

        // 查询分组
        SchoolbagGroupDO group = schoolbagGroupService.lambdaQuery().eq(BaseEntity::getId, request.getGroupId()).one();
        AssertUtil.assertNotNull(group, "书包分组不存在");

        // RAS书包校验-是否存在或审核通过
        WrapAuditListRequest auditListRequest = new WrapAuditListRequest();
        auditListRequest.setId(category.getRasId());
        RasBaseResponse<WrapAuditListResponse> auditResponse = rasClient.wrapAuditList(auditListRequest);
        WrapAuditListResponse wrapAuditListResponse = JSON.parseObject(JSON.toJSONString(auditResponse.getData()), WrapAuditListResponse.class);
        List<WrapAuditListResponse.RecordsDTO> recordsDTOS = wrapAuditListResponse.getRecords();
        AssertUtil.assertTrue(CollectionUtils.isNotEmpty(recordsDTOS), "书包类型在RAS侧尚未通过审核或者不存在");
        WrapAuditListResponse.RecordsDTO recordsDTO = recordsDTOS.get(0);
        GoodsBindingRequest.WrapDTO wrapDTO = new GoodsBindingRequest.WrapDTO(recordsDTO);

        // 第二步：处理书包
        List<GoodsBindingRequest> list = Lists.newArrayList();
        Integer groupIndex = 0;
        for (SchoolbagGroupBagOperationRequest item : request.getBagList()) {
            // TODO MOCK RAS
//            AssertUtil.assertNotNull(item.getBagRsaUrl(), "RAS书包全码值不能为空");
            AssertUtil.assertNotEmpty(item.getStorageBooks(), "书包书籍不能为空");
//                AssertUtil.assertTrue(item.getStorageBooks().size() == specificationInteger, String.format("书包书籍本书必需为%s本", specificationInteger));

            GoodsBindingRequest bindingRequest = new GoodsBindingRequest();
            bindingRequest.setWrap(wrapDTO);
            bindingRequest.setAbstring(item.getBagRasUrl());

            // 1.书包
            SchoolbagGroupBagDO entity = new SchoolbagGroupBagDO();
            entity.setCategoryId(request.getCategoryId());
            entity.setSpecId(spec.getId());
            entity.setGroupId(group.getId());
            entity.setGroupIndex(++groupIndex);
            entity.setBagCode(item.getBagCode());
            entity.setBagRasUrl(item.getBagRasUrl());
            if (save(entity)) {

                // 2.书包里面的实体书籍
                List<String> abstringList = Lists.newArrayList();
                for (SchoolbagGroupBagBooksOperationVO booksItem : item.getStorageBooks()) {
                    AssertUtil.assertNotNull(booksItem.getStorageBookRasCode(), "RAS编码不能为空");
                    AssertUtil.assertNotNull(booksItem.getStorageBookRasUrl(), "RAS全码值不能为空");
                    // 查询书籍全码值
                    SchoolbagBooksStorageDO storage = schoolbagBooksStorageService.lambdaQuery()
                            .eq(SchoolbagBooksStorageDO::getRasCode, booksItem.getStorageBookRasCode())
                            .eq(SchoolbagBooksStorageDO::getRasUrl, booksItem.getStorageBookRasUrl())
                            .one();
                    AssertUtil.assertNotNull(storage, "书籍不存在");

                    SchoolbagGroupBagBooksRequest booksRequest = new SchoolbagGroupBagBooksRequest();
                    booksRequest.setCategoryId(request.getCategoryId());
                    booksRequest.setGroupId(request.getGroupId());
                    booksRequest.setBagId(entity.getId());
                    booksRequest.setBookId(booksItem.getBookId());
                    booksRequest.setStorageBookId(storage.getId());
                    schoolbagGroupBagBooksService.add(booksRequest);
                    // 将书籍修改为被占用
                    schoolbagBooksStorageService.lambdaUpdate().eq(BaseEntity::getId, booksItem.getStorageBookId()).set(SchoolbagBooksStorageDO::getIsUse, 1).update();
                    abstringList.add(storage.getRasUrl());
                }
                bindingRequest.setAbstringList(abstringList);
            }
            list.add(bindingRequest);
        }
        return true;
    }

    @Transactional
    @Override
    public Boolean batchUpdate(SchoolbagGroupBagListOperationRequest request) {
        // todo 书包和书籍都是ras码为准，如果不存在则认为是书包整个更新或者是书包里面的数据进行了进行
        return true;
    }

    @Transactional
    public Boolean batchAdd(SchoolbagGroupBagBatchRequest request) {
        // 第一步：校验
        AssertUtil.assertNotNull(request.getCategoryId(), "书包类型id不能为空");
        AssertUtil.assertNotNull(request.getGroupId(), "书包所属分组不能为空");
        AssertUtil.assertNotEmpty(request.getBagList(), "书包所属分组不能为空");
        AssertUtil.assertTrue(request.getBagList().size() == 12, "书包个数必须为12个");

        SchoolbagDO schoolbagDO = schoolbagService.lambdaQuery().eq(BaseEntity::getId, request.getCategoryId()).last("limit 1").one();
        AssertUtil.assertNotNull(schoolbagDO, "书包类型不存在");
        String specification = schoolbagDO.getSpecification();
        AssertUtil.assertNotNull(specification, "书包规格期数不能为空");
        AssertUtil.assertTrue(NumberUtil.isNumber(specification), "书包规格期数必须为数字");

        SchoolbagSpecificationDO schoolbagSpec = schoolbagSpecificationService.lambdaQuery().eq(SchoolbagSpecificationDO::getSchoolbagId, schoolbagDO.getId()).eq(BaseEntity::getId, request.getSpecId()).last("limit 1").one();
        AssertUtil.assertNotNull(schoolbagSpec, "书包规格不存在");

        SchoolbagGroupDO schoolbagGroup = schoolbagGroupService.lambdaQuery().eq(SchoolbagGroupDO::getCategoryId, schoolbagDO.getId()).eq(SchoolbagGroupDO::getSpecId, schoolbagSpec.getId()).last("limit 1").one();
        AssertUtil.assertNotNull(schoolbagGroup, "书包分组不存在");

        // RAS书包校验-是否存在或审核通过
        WrapAuditListRequest auditListRequest = new WrapAuditListRequest();
        auditListRequest.setId(schoolbagDO.getRasId());
        RasBaseResponse<WrapAuditListResponse> auditResponse = rasClient.wrapAuditList(auditListRequest);
        WrapAuditListResponse wrapAuditListResponse = JSON.parseObject(JSON.toJSONString(auditResponse.getData()), WrapAuditListResponse.class);
        List<WrapAuditListResponse.RecordsDTO> recordsDTOS = wrapAuditListResponse.getRecords();
        AssertUtil.assertTrue(CollectionUtils.isNotEmpty(recordsDTOS), "书包类型在RAS侧尚未通过审核或者不存在");
        WrapAuditListResponse.RecordsDTO recordsDTO = recordsDTOS.get(0);
        GoodsBindingRequest.WrapDTO wrapDTO = new GoodsBindingRequest.WrapDTO(recordsDTO);

        // 第二步：处理书包
        List<GoodsBindingRequest> list = Lists.newArrayList();
        Integer groupIndex = 0;
        for (SchoolbagGroupBagRequest item : request.getBagList()) {
            // TODO MOCK RAS
//            AssertUtil.assertNotNull(item.getBagRsaUrl(), "RAS书包全码值不能为空");

            GoodsBindingRequest bindingRequest = new GoodsBindingRequest();
            bindingRequest.setWrap(wrapDTO);
            bindingRequest.setAbstring(item.getBagRasUrl());

            // 1.书包
            SchoolbagGroupBagDO entity = SchoolbagGroupBagDtoMapper.INSTANCE.request2DO(item);
            entity.setCategoryId(request.getCategoryId());
            entity.setSpecId(schoolbagDO.getId());
            entity.setGroupId(request.getGroupId());
            entity.setGroupIndex(++groupIndex);
            if (save(entity)) {
                AssertUtil.assertNotEmpty(item.getStorageBooks(), "书包书籍不能为空");
//                AssertUtil.assertTrue(item.getStorageBooks().size() == specificationInteger, String.format("书包书籍本书必需为%s本", specificationInteger));

                // 2.书包里面的实体书籍
                List<String> abstringList = Lists.newArrayList();
                for (SchoolbagGroupBagBooksRequest booksItem : item.getStorageBooks()) {
                    SchoolbagGroupBagBooksRequest booksRequest = new SchoolbagGroupBagBooksRequest();
                    booksRequest.setCategoryId(request.getCategoryId());
                    booksRequest.setGroupId(request.getGroupId());
                    booksRequest.setBagId(entity.getId());
                    booksRequest.setBookId(booksItem.getBookId());
                    booksRequest.setStorageBookId(booksItem.getStorageBookId());
                    schoolbagGroupBagBooksService.add(booksRequest);
                    // 将书籍修改为被占用
                    schoolbagBooksStorageService.lambdaUpdate().eq(BaseEntity::getId, booksItem.getStorageBookId()).set(SchoolbagBooksStorageDO::getIsUse, 1).update();
                    // 查询书籍全码值
                    SchoolbagBooksStorageVO storageVO = schoolbagBooksStorageService.getByKey(booksItem.getStorageBookId());
                    AssertUtil.assertNotNull(storageVO, "书籍不存在");
                    AssertUtil.assertNotNull(storageVO.getRasUrl(), "书籍RAS全码值不能为空");
                    abstringList.add(storageVO.getRasUrl());
                }
                bindingRequest.setAbstringList(abstringList);
            }
            list.add(bindingRequest);
        }
        //TODO MOCK RAS
        AssertUtil.assertNotEmpty(list, "待激活的书包、书籍不存在");
//        for (GoodsBindingRequest bindingRequest : list) {
//            rasClient.goodsBinding(bindingRequest);
//        }
        return true;
    }

    @Override
    public SchoolbagGroupBagListOperationVO getBagListByGroupId(long groupId) {
        AssertUtil.assertNotNull(groupId, "书包规格id不能为空");
        SchoolbagGroupDO group = schoolbagGroupService.lambdaQuery()
                .eq(BaseEntity::getId, groupId)
                .last("limit 1")
                .one();
        AssertUtil.assertNotNull(group, "书包分组不能为空");

        SchoolbagGroupBagListOperationVO operationVO = new SchoolbagGroupBagListOperationVO();
        operationVO.setCategoryId(group.getCategoryId());
        operationVO.setSpecId(group.getId());
        operationVO.setGroupId(group.getId());

        List<SchoolbagGroupBagDO> groupBagList = this.lambdaQuery().eq(SchoolbagGroupBagDO::getGroupId, group.getId()).list();
        if (CollectionUtils.isEmpty(groupBagList)) {
            // 新增链路
            List<SchoolbagGroupBagOperationVO> bagList = Lists.newArrayList();

            // 查询规格下的所有分期
            SchoolbagPhaseRequest request = new SchoolbagPhaseRequest();
            request.setCategoryId(group.getCategoryId());
            request.setSpecId(group.getSpecId());
            List<SchoolbagPhaseVO> phases = schoolbagPhaseService.listQuery(request);

            // 查询每一个分期下的书籍
            for (SchoolbagPhaseVO phase : phases) {
                SchoolbagGroupBagOperationVO bagOperationVO = new SchoolbagGroupBagOperationVO();
                bagOperationVO.setCategoryId(group.getCategoryId());
                bagOperationVO.setSpecId(group.getSpecId());
                bagOperationVO.setGroupId(group.getId());

                // 查询分期下的书籍
                SchoolbagPhaseBooksRequest booksRequest = new SchoolbagPhaseBooksRequest();
                booksRequest.setCategoryId(group.getCategoryId());
                booksRequest.setSpecId(group.getSpecId());
                booksRequest.setPhaseId(phase.getId());
                List<SchoolbagPhaseBooksVO> phaseBooks = schoolbagPhaseBooksService.listQuery(booksRequest);
                AssertUtil.assertNotEmpty(phaseBooks, "分组对应的规格数据不足，存在分期中没有书籍的情况，请检查");

                List<SchoolbagGroupBagBooksOperationVO> booksList = phaseBooks.stream().map(item -> {
                    SchoolbagGroupBagBooksOperationVO book = new SchoolbagGroupBagBooksOperationVO();
                    book.setCategoryId(group.getCategoryId());
                    book.setGroupId(group.getId());
                    book.setTitle(item.getTitle());
                    book.setBookId(item.getBooksId());
                    book.setPicture(item.getPicture());
                    return book;
                }).collect(Collectors.toList());
                bagOperationVO.setStorageBooks(booksList);
                bagList.add(bagOperationVO);
            }
            operationVO.setBagList(bagList);
        } else {
            // 已经存在书包链路
            List<SchoolbagGroupBagOperationVO> bagList = Lists.newArrayList();
            for (SchoolbagGroupBagDO bag : groupBagList) {
                SchoolbagGroupBagOperationVO bagOperationVO = new SchoolbagGroupBagOperationVO();
                bagOperationVO.setId(bag.getId());
                bagOperationVO.setCategoryId(group.getCategoryId());
                bagOperationVO.setSpecId(group.getSpecId());
                bagOperationVO.setGroupId(group.getId());
                bagOperationVO.setGroupIndex(bag.getGroupIndex());
                bagOperationVO.setStatus(bag.getStatus());
                bagOperationVO.setBagCode(bag.getBagCode());
                bagOperationVO.setBagRasUrl(bag.getBagRasUrl());

                List<SchoolbagGroupBagBooksDO> bagBooksList = schoolbagGroupBagBooksService.lambdaQuery()
                        .eq(SchoolbagGroupBagBooksDO::getCategoryId, group.getCategoryId())
                        .eq(SchoolbagGroupBagBooksDO::getGroupId, group.getId())
                        .eq(SchoolbagGroupBagBooksDO::getBagId, bag.getId())
                        .list();
                AssertUtil.assertNotEmpty(bagBooksList, "分组书包存在书包中书籍为空的情况，请检查");

                List<SchoolbagGroupBagBooksOperationVO> booksList = bagBooksList.stream().map(item -> {
                    SchoolbagGroupBagBooksOperationVO book = new SchoolbagGroupBagBooksOperationVO();
                    book.setId(item.getId());
                    book.setCategoryId(group.getCategoryId());
                    book.setGroupId(group.getId());
                    book.setBagId(item.getBagId());
                    book.setStorageBookId(item.getStorageBookId());
                    SchoolbagBooksStorageDO one = schoolbagBooksStorageService.lambdaQuery().eq(BaseEntity::getId, item.getStorageBookId()).one();
                    AssertUtil.assertNotNull(one, "分组书包书籍数据异常，请检查");
                    book.setStorageBookRasCode(one.getRasCode());
                    book.setStorageBookRasUrl(one.getRasUrl());
                    SchoolbagBooksVO booksVO = schoolbagBooksService.getByKey(item.getBookId());
                    if (booksVO != null) {
                        // 书籍信息
                        MallBooksDO mallBooksDO = mallBooksMapper.selectDOById(booksVO.getMallBooksId());
                        if (mallBooksDO != null) {
                            book.setTitle(mallBooksDO.getTitle());
                            book.setBookId(booksVO.getId());
                            book.setPicture(mallBooksDO.getPicture());
                        }
                    }
                    return book;
                }).collect(Collectors.toList());
                bagOperationVO.setStorageBooks(booksList);
                bagList.add(bagOperationVO);
            }
            operationVO.setBagList(bagList);
        }

        return operationVO;
    }

    @Override
    public Boolean check(SchoolbagBookCheckRequest request) {
        AssertUtil.assertNotNull(request.getSchoolbagBookId(), "书包书籍id不能为空");
        AssertUtil.assertNotNull(request.getBookRasCode(), "书籍(ras编码)不能为空");
        AssertUtil.assertNotNull(request.getBookRsaUrl(), "书籍(ras全码值)不能为空");

        return schoolbagBooksStorageService.lambdaQuery()
                .eq(SchoolbagBooksStorageDO::getBooksId, request.getSchoolbagBookId())
                .eq(SchoolbagBooksStorageDO::getRasCode, request.getBookRasCode())
                .eq(SchoolbagBooksStorageDO::getRasUrl, request.getBookRsaUrl())
                .exists();
    }
}
